package cn.birdbaby.plugins.refactorgen;

import com.intellij.internal.statistic.eventLog.util.StringUtil;
import com.intellij.openapi.application.ReadAction;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.bouncycastle.util.Arrays;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author llorando 5/8/24 10:54 pm
 */
public class BBRefactorContext {
    //懒汉，在确定需要使用时，再去初始化
    private String oldName;

    private String newName;

    private PsiElement element;

    //待修改的，被Gen注解标记的文件
    private List<PsiClass> psiClassList;

    public BBRefactorContext(PsiElement element) {
        this.element = element;
        psiClassList = new ArrayList<>();
    }

    public String getNewName() {
        if (this.newName == null) {
            initNewName();
        }
        return this.newName;
    }

    public void initNewName() {
        if (element instanceof PsiClass) {
            PsiFile psiFile = element.getContainingFile();
            String newName = ReadAction.compute(() -> {
                PsiPackageStatement psiPackageStatement = PsiTreeUtil.findChildOfType(psiFile, PsiPackageStatement.class);
                //只考虑一级目录
                int begin = psiPackageStatement.getPackageName().lastIndexOf(".");
                return psiPackageStatement.getPackageName().substring(begin + 1);
            });
            this.newName = newName;
        } else if (element instanceof PsiPackage) {
            this.newName = ((PsiPackage) element).getName();
        } else {
            throw new RuntimeException("目前只支持PsiClass、PsiPackage类型的重构");
        }
    }

    public void initOldName() {
        if (element instanceof PsiClass) {
            //从Gen原来的注解中获取原来的包名
            PsiClass psiClass = (PsiClass) element;
            findDomainEntityThenDoSomething(psiClass, (anno, ele) -> {
                extractOldName(anno);
                return true;
            });
        } else if (element instanceof PsiPackage) {
            //遍历package中的类，在存在Gen注解标记的类头拿到原来的包名；
            PsiClass[] psiClasses = ((PsiPackage) element).getClasses();
            if (Arrays.isNullOrEmpty(psiClasses)) return;
            for (int i = 0; i < psiClasses.length && !StringUtil.isEmpty(this.oldName); i++) {
                PsiClass psiClass = psiClasses[i];
                findDomainEntityThenDoSomething(psiClass, (anno, ele) -> {
                    if (StringUtil.isEmpty(oldName)) {
                        extractOldName(anno);
                    }
                    return true;
                });
            }

        } else {
            throw new RuntimeException("目前只支持PsiClass、PsiPackage类型的重构");
        }
    }

    public String getOldName() {
        if (this.oldName == null) {
            initOldName();
        }
        return this.oldName;
    }

    /**
     * 获取file中的注解列表，判断是否存在@Table和@Entity
     * 思考一个问题，如果我希望把psiPackage作为参数传递进来，让这个能力可以暴露给外部使用，应该怎么办？
     * psiPackage-> {} 响应式编程，把操作作为参数传递出去
     *
     * @return
     */
    public List<PsiClass> collectDomainFiles() {
        if (element instanceof PsiClass) {
            findDomainEntityThenDoSomething((PsiClass) element, (anno, ele) -> psiClassList.add(ele));
        } else if (element instanceof PsiPackage) {
            PsiPackage psiPackage = (PsiPackage) element;
            PsiClass @NotNull [] psiClasses = psiPackage.getClasses();
            if (Arrays.isNullOrEmpty(psiClasses)) return this.psiClassList;
            for (int i = 0; i < psiClasses.length; i++) {
                PsiClass psiClass = psiClasses[i];
                findDomainEntityThenDoSomething(psiClass, (anno, ele) -> {
                    if (StringUtil.isEmpty(oldName)) {
                        extractOldName(anno);
                    }
                    return psiClassList.add(ele);
                });

            }
        }
        return this.psiClassList;
    }

    private void extractOldName(PsiAnnotation psiAnnotation) {
        PsiAnnotationMemberValue value = psiAnnotation.findAttributeValue("pkgName");
        String patternString = "domain\\.(.*?)(?=\\.)";
        Pattern pattern = Pattern.compile(patternString);
        Matcher matcher = pattern.matcher(value.getText());
        if (matcher.find()) {
            this.oldName = matcher.group(1);
        }
    }

    public void findDomainEntityThenDoSomething(PsiClass psiClass, BiFunction<PsiAnnotation, PsiClass, Boolean> biFunction) {
        Collection<PsiAnnotation> psiAnnotations = ReadAction.compute(() ->
                PsiTreeUtil.findChildrenOfAnyType(psiClass, PsiAnnotation.class)
        );
        if (psiAnnotations.isEmpty()) return;
        for (PsiAnnotation psiAnnotation : psiAnnotations) {
            String name = ReadAction.compute(() -> psiAnnotation.getNameReferenceElement().getReferenceName());
            if (name.startsWith("Gen")) {
                biFunction.apply(psiAnnotation, psiClass);
                break;
            }
        }
    }

    private List<PsiClass> getPsiClassList() {
        return this.psiClassList;
    }

    public void renamePackageNameInGenAnnotation() {

    }
}
